package de.recipeminer.tools;

import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import org.apache.log4j.Logger;

import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Properties;

public class Config {
    protected String MAVEN_PROPERTY_FILE = "maven.properties";
    private String minerEnv;
    public static final String chefkoch_charset_encoding_string = "ISO-8859-1"; //TODO: insert proper encoding information
    private static Logger logger = Logger.getLogger(Config.class);
    private static Config instance = new Config();
    private Properties mavenPropertiesCache = null;

    private Config() {
        minerEnv = System.getenv("MINERENV");
        if (minerEnv == null || minerEnv.isEmpty()) {
            minerEnv = "development";
        }
    }

    public static Config getInstance() {
        return instance;
    }

    protected Properties getMavenProperties() {
        if (mavenPropertiesCache == null) {
            mavenPropertiesCache = new Properties();
            try {
                mavenPropertiesCache.load(getResourceStream(MAVEN_PROPERTY_FILE));
            } catch (IOException e) {
                String msg = String.format("An error occurred attempting to open %s:", MAVEN_PROPERTY_FILE);
                throw new RuntimeException(msg, e);
            }
        }
        return mavenPropertiesCache;
    }

    public String getMinerEnv() {
        return minerEnv;
    }

    public InputStream getResourceStream(String relPath) {
        try {
            return new BufferedInputStream(Resources.newInputStreamSupplier(getResource(relPath, true)).getInput());
        } catch (IOException e) {
            throw new UnableToLocateResourceException(relPath, e);
        }
    }

    public BufferedReader getResourceReader(String relPath) {
        try {
            return new BufferedReader(Resources.newReaderSupplier(getResource(relPath, true), Charsets.UTF_8).getInput());
        } catch (IOException e) {
            throw new UnableToLocateResourceException(relPath,e);
        }
    }

    public File getResourceFile(String relPath) {
        return new File(getResource(relPath, true).getPath());
    }

    public File getResourceFile(String relPath, boolean useEnv) {
        return new File(getResource(relPath, useEnv).getPath());
    }

    public URL getResource(String relPath, boolean useEnv) {
        URL url = null;
        if (useEnv) {
            String envRelPath = Joiner.on(File.separator).join(minerEnv, relPath);
            url = Thread.currentThread().getContextClassLoader().getResource(envRelPath);
        }
        if (!useEnv || url == null) {
            url = Thread.currentThread().getContextClassLoader().getResource(relPath);
        }
        if(url == null) {
            throw new UnableToLocateResourceException(relPath);
        }
        return url;
    }

    class UnableToLocateResourceException extends RuntimeException {
        public UnableToLocateResourceException(String resourceDescriptor) {
            super(String.format("Unable to locate resource '%s' using classloader %s.",
                    resourceDescriptor,
                    Thread.currentThread().getContextClassLoader().getClass().getName()));
        }

        public UnableToLocateResourceException(String resourceDescriptor, Throwable cause) {
            super(String.format("Unable to locate resource '%s' using classloader %s.",
                    resourceDescriptor,
                    Thread.currentThread().getContextClassLoader().getClass().getName()), cause);
        }
    
    }

    public static void main(String[] args) {
        File log4j = Config.getInstance().getResourceFile("log4j.properties");
        List<String> entries = Lists.newLinkedList();
        try {
            entries = Resources.readLines(Resources.getResource("classpath.list"), Charset.defaultCharset());
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(Joiner.on("\n").join(entries.toArray()));

        System.out.println(log4j != null ? log4j : "NULL");

    }

    static public enum Environment {
        DEVELOPMENT("development"),
        TEST("test"),
        PRODUCTION("production");

        private String envValue;

        Environment(String envValue) {
            this.envValue = envValue;
        }

        public boolean isActive() {
            return Config.getInstance().minerEnv.equals(envValue);
        }
    }

}